package scheduler

import (
	"smart-flow/server/logger"
	"smart-flow/server/task"
	"smart-flow/server/utils"
	"sync/atomic"
	"time"

	"go.uber.org/zap"

	"github.com/go-co-op/gocron/v2"
	"github.com/google/uuid"
)

type Scheduler struct {
	scheduler gocron.Scheduler
	pausing   atomic.Bool // 调度器暂停状态
}

func (s *Scheduler) Init() {
	s.scheduler, _ = gocron.NewScheduler(gocron.WithStopTimeout(30 * time.Second))
}

func (s *Scheduler) Start() {
	s.scheduler.Start()
}

func (s *Scheduler) Shutdown() {
	_ = s.scheduler.Shutdown()
}

func (s *Scheduler) Stop() bool {
	if len(s.scheduler.Jobs()) == 0 {
		return true
	}
	err := s.scheduler.StopJobs()
	if err != nil {
		logger.Logger.Error("[任务] Scheduler停止Job失败", zap.Error(err))
		return false
	}
	return true
}

func (s *Scheduler) Pause() {
	s.pausing.Store(true)
}

func (s *Scheduler) Resume() {
	s.pausing.Store(false)
}

func (s *Scheduler) Pausing() bool {
	return s.pausing.Load()
}

func (s *Scheduler) Build(task *task.FlowTask) bool {
	for _, j := range s.scheduler.Jobs() {
		if task.Id() == j.ID().String() {
			return false
		}
		_ = s.scheduler.RemoveJob(j.ID())
	}
	if task.Unschedule() {
		return false
	}
	newJob, begin, remain := s.doBuild(task)
	if newJob == nil {
		logger.Logger.Error("[任务] Scheduler构建Job失败", zap.Any("job", task.GetJob()))
		return false
	}
	if remain > 0 {
		logger.Logger.Info("[任务] Scheduler构建Job完成", zap.Any("job", task.GetJob()), zap.String("startRunTime", utils.TimeFormat(begin)),
			zap.String("stopRunTime", utils.TimeFormat(time.Now().Add(remain))))
	} else {
		logger.Logger.Info("[任务] Scheduler构建Job完成", zap.Any("job", task.GetJob()), zap.String("startRunTime", utils.TimeFormat(begin)),
			zap.String("stopRunTime", "forever"))
	}
	s.Start()
	return true
}

func (s *Scheduler) doBuild(task *task.FlowTask) (*gocron.Job, time.Time, time.Duration) {
	startRunTime, remaining, err := task.CalcSchedulerTime()
	if err != nil {
		return nil, startRunTime, remaining
	}
	jobDef := gocron.DurationJob(time.Minute)
	jobOpts := []gocron.JobOption{
		gocron.WithIdentifier(uuid.MustParse(task.Id())),
		gocron.WithSingletonMode(gocron.LimitModeReschedule),
		gocron.WithStartAt(gocron.WithStartDateTime(startRunTime)),
	}
	newJob, err := s.scheduler.NewJob(jobDef, gocron.NewTask(task.Run), jobOpts...)
	if err != nil {
		logger.Logger.Error("[任务] Scheduler添加Job失败", zap.Any("job", task.GetJob()), zap.Error(err))
		return nil, startRunTime, remaining
	}
	if remaining > 0 {
		time.AfterFunc(remaining, func() {
			errRemove := s.scheduler.RemoveJob(newJob.ID())
			if errRemove != nil {
				logger.Logger.Warn("[任务] Scheduler删除Job失败", zap.Any("job", task.GetJob()), zap.Error(errRemove))
				return
			}
			task.Finish()
			logger.Logger.Info("[任务] Scheduler执行结束", zap.Any("job", task.GetJob()))
		})
	}
	return &newJob, startRunTime, remaining
}
